package data.converter;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.StringWriter;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.json.simple.JSONValue;

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonElement;
import com.google.gson.JsonParser;

import data.converter.parser.ParserToCustomer;
import data.converter.parser.ParserToPerson;
import data.converter.parser.ParserToProduct;
import data.converter.parser.ReadPlainFile;



public class DataConverter {
	
	private static final Logger logger = Logger.getLogger(DataConverter.class.getName());

	/**
	 * @param args
	 * @throws IOException 
	 */

	public static void main(String[] args) throws IOException {
		// TODO Auto-generated method stub
		String defaultDirectory = "data/";
		if(args.length == 1){
			defaultDirectory = args[0];
		}
		DataConverter converter = new DataConverter();
		
		String personInput = defaultDirectory + "Persons.dat";
		String customerInput = defaultDirectory + "Customers.dat";
		String productInput = defaultDirectory + "Products.dat";
		
		String personOutput = defaultDirectory + "Persons.json";
		String customerOutput = defaultDirectory + "Customers.json";
		String productOutput = defaultDirectory + "Products.json";
		//writePersonJsonFile needs to execute firstly, because the cusomter and prodent depending on it
		ArrayList personList = converter.writePersonJsonFile(new File(personInput), personOutput);
		converter.writeCustomerJsonFile(new File(customerInput), personList, customerOutput);
		converter.writeProductJsonFile(new File(productInput), personList, productOutput);
	}
	
	/**
	 * 
	 * @param file
	 * @param output
	 * @return list<Person>
	 * @throws IOException
	 * Generate Persons.json file
	 */
	public ArrayList writePersonJsonFile(File file, String output) throws IOException {
		List<String> lineList = getFileContent(file);
		if (lineList == null || lineList.isEmpty()) {
			logger.log(Level.INFO, "NO data to deal");
			return null;
		}
		ParserToPerson mapping = new ParserToPerson();
		ArrayList personList = new ArrayList ();
		
		for(String strValue: lineList) {
			personList.add(mapping.converterToPerson(strValue));
		}
		LinkedHashMap map = new LinkedHashMap();
		map.put("persons", personList);
		StringWriter out = new StringWriter();
		JSONValue.writeJSONString(map, out);
		String uglyJSONString = out.toString();
		writeJsonStrToFile(output,uglyJSONString);
		return personList;
	}
	
	/**
	 * 
	 * @param file
	 * @param personList
	 * @param output
	 * @throws IOException
	 * Generate Customers.json file
	 */
	public void writeCustomerJsonFile(File file, ArrayList personList, String output) throws IOException {
		List<String> lineList = getFileContent(file);
		if (lineList == null || lineList.isEmpty()) {
			logger.log(Level.INFO, "NO data to deal");
			return;
		}
		ParserToCustomer mapping = new ParserToCustomer();
		mapping.setPersonList(personList);
		ArrayList customerList = new ArrayList();
		for(String strValue: lineList) {
			customerList.add(mapping.converterToCustomer(strValue));
		}
		LinkedHashMap map = new LinkedHashMap();
		map.put("customers", customerList);
		StringWriter out = new StringWriter();
		JSONValue.writeJSONString(map, out);
		String uglyJSONString = out.toString();
		writeJsonStrToFile(output,uglyJSONString);
	}
	
	/**
	 * @param file
	 * @param personList
	 * @param output
	 * @throws IOException
	 * Generate Products.json file
	 */
	public void writeProductJsonFile(File file, ArrayList personList, String output) throws IOException {
		List<String> lineList = getFileContent(file);
		if (lineList == null || lineList.isEmpty()) {
			logger.log(Level.INFO, "NO data to deal");
			return;
		}
		ParserToProduct mapping = new ParserToProduct();
		mapping.setPersonList(personList);
		ArrayList productList = new ArrayList();
		for(String strValue: lineList) {
			productList.add(mapping.getProduct(strValue));
		}
		LinkedHashMap map = new LinkedHashMap();
		map.put("products", productList);
		StringWriter out = new StringWriter();
		JSONValue.writeJSONString(map, out);
		String uglyJSONString = out.toString();
		writeJsonStrToFile(output,uglyJSONString);
	}
	
	/**
	 * @param fileName
	 * If generated file has existed, delete it firstly
	 */
	private void deleteExistedFile(String fileName) {
		File outputFile = new File(fileName);
		if(outputFile.exists()){
			outputFile.delete();
		}
	}
	
	public List<String> getFileContent(File file){
		ReadPlainFile readFile = new ReadPlainFile(file);
		List<String> lineList;
		try {
			lineList = readFile.readFileToList();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			logger.log(Level.SEVERE, e.getMessage());
			return null;
		}
		return lineList;
	}
	
	/**
	 * Format JSON string to file
	 * @param outputFile, uglyJSONString
	 */
	private void writeJsonStrToFile(String outputFile, String uglyJSONString) {
		Gson gson = new GsonBuilder().setPrettyPrinting().create();
		JsonParser jp = new JsonParser();
		JsonElement je = jp.parse(uglyJSONString);
		String prettyJsonString = gson.toJson(je);
		deleteExistedFile(outputFile);
		logger.log(Level.INFO, "Generated product file: " + outputFile);
		BufferedWriter writer;
		try {
			writer = new BufferedWriter(new FileWriter(outputFile));
			writer.write(prettyJsonString);
			writer.close();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			logger.log(Level.SEVERE, "IOException: ", e);
		}
		
	}
}
